﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AMVInfoSpace;
using System.IO;

namespace AMVCommander
{
    public partial class FormAmvInfo : Form
    {
        List<AMVInfo> AmvShowList = new List<AMVInfo>();

        AMVInfo SelAmv { get { if (lv.SelectedIndices.Count == 0)return null; return (AMVInfo)AmvShowList[lv.SelectedIndices[0]]; } }

        /// <summary>исключенные теги. Запись, где есть хотя бы 1 исключенный тег не показывается</summary>
        List<string> ExTags = new List<string>();
        /// <summary>закрепленные теги. Запись, где нет хотя бы одного закрепленного тега не показывается</summary>
        List<string> FixTags = new List<string>();
        /// <summary>список тегов, по которым записей по фильтру нет</summary>
        List<string> EmptyTags = new List<string>();
        Color clrDisabledItem = Color.FromArgb(197, 124, 124);

        public List<Column> ClmL = new List<Column>();

        public FormAmvInfo()
        {
            InitializeComponent();

            ClmL.Add(new Column(ColumnType.Name, 200, true));
            ClmL.Add(new Column(ColumnType.Rating, 50, true));
            ClmL.Add(new Column(ColumnType.Tag, 200, true));
            ClmL.Add(new Column(ColumnType.Author, 100, true));
            ClmL.Add(new Column(ColumnType.Music, 200, true));
            ClmL.Add(new Column(ColumnType.Anime, 200, true));
            ClmL.Add(new Column(ColumnType.Awards, 200, true));
        }

        private void FormAmvInfo_Shown(object sender, EventArgs e)
        {
            if (Gl.infoL.Count == 0) Gl.LoadAmvInfoList();
            LoadWatch();

            #region *** временный метод переформатирования тегов *********
            if (false)
            {
                AmvHtmlParser.fPathAkrossTagReplList = Application.StartupPath + "\\Tools\\AMVNewsParser\\AkrossTagReplList.csv";
                AmvHtmlParser.akrossTagReplList = new AmvHtmlParser.AkrossTagReplList();
                foreach (AMVInfo aInf in Gl.infoL)
                {
                    switch (aInf.Site)
                    {
                        case SITE.AMVNews:
                            {
                                for (int i = 0; i < aInf.TagGenre.Count; i++)
                                {
                                    if (aInf.TagGenre[i].Contains("20"))
                                    {
                                        aInf.TagOther.Add(aInf.TagGenre[i]);
                                        aInf.TagGenre.RemoveAt(i);
                                        i--;
                                    }
                                }
                                break;
                            }
                        case SITE.Akross:
                            {
                                for (int i = 0; i < aInf.TagOther.Count; i++)
                                {
                                    //Теги для замены Akross
                                    List<string> sl = AMVInfo.SplitTextForFind(aInf.TagOther[i]);
                                    bool bGenre = false;
                                    foreach (string keyWord in sl)
                                    {
                                        if (AmvHtmlParser.akrossTagReplList.RepList.ContainsKey(keyWord))
                                        {
                                            foreach (string tag in AmvHtmlParser.akrossTagReplList.RepList[keyWord])
                                            {
                                                if (!aInf.TagGenre.Contains(tag))
                                                    aInf.TagGenre.Add(tag);
                                                bGenre = true;
                                            }
                                        }
                                    }
                                    if (bGenre)
                                    {
                                        aInf.TagOther.RemoveAt(i);
                                        i--;
                                    }
                                    else if (sl.Count == 0)
                                    {
                                        aInf.TagOther.RemoveAt(i);
                                        i--;
                                    }
                                }
                                break;
                            }
                        case SITE.CreaCon:
                            {
                                for (int i = 0; i < aInf.TagGenre.Count; i++)
                                {
                                    if (AmvHtmlParser.ReplTagGanreForCreaCon.ContainsKey(aInf.TagGenre[i].ToUpper()))
                                    {
                                        aInf.TagGenre[i] = AmvHtmlParser.ReplTagGanreForCreaCon[aInf.TagGenre[i].ToUpper()];
                                    }
                                }

                                List<string> newTagOther = new List<string>();
                                for (int i = 0; i < aInf.TagOther.Count; i++)
                                {
                                    string[] sl = aInf.TagOther[i].Split(',');
                                    foreach (string tagOther in sl)
                                        if (tagOther.Trim() != "" && !newTagOther.Contains(tagOther.Trim()))
                                            newTagOther.Add(tagOther.Trim());
                                }
                                aInf.TagOther = newTagOther;
                                break;
                            }
                    }
                }
            }
            #endregion *** временный метод переформатирования тегов *********

            AMVInfo.SortMode = AMVInfo.SortMODE.Name;
            AMVInfo.SortDesc = false;
            Gl.infoL.Sort();

            RefillColumns();

            foreach (AMVInfo aInf in Gl.infoL)
            {
                aInf.Itm = new ListViewItem();
                UpdateItm(aInf.Itm, lv.Columns, aInf);
            }

            ReFillAmvInfo(false);
            RefillLvTags();
            SetFltIco();
        }

        void RefillColumns()
        {
            lv.Columns.Clear();
            foreach (Column clm in ClmL)
            {
                if (!clm.Visible) continue;

                ColumnHeader clmn = new ColumnHeader(9);
                clmn.Text = clm.Name;
                clmn.Width = clm.Width;
                clmn.Tag = clm;

                if (clm.Tp == ColumnType.Len) clmn.TextAlign = HorizontalAlignment.Right;

                lv.Columns.Add(clmn);
            }

        }

        /// <summary>перезаполнение списка с учетом фильтрации
        /// при изменении списка или при изменении параметров фильтрации
        /// <param name="ActAmvRowId">RowID текущго amv (если -1, выделенного amv текущего нет. Если выделеное amv не входит в фильтрацию, выделение снимается)</param>
        void ReFillAmvInfo(bool SaveSelected)
        {
            try
            {
                // если сохранять выделение, запоминаем выделенные AMV
                List<AMVInfo> selectedRecs = new List<AMVInfo>();
                if (SaveSelected)
                {
                    foreach (int ind in lv.SelectedIndices) selectedRecs.Add(AmvShowList[ind]);
                }

                // для разового обновления
                List<AMVInfo> tmpAmvShowList = new List<AMVInfo>();

                // иконки столбцов (на наличие фильтрации и сортировки)
                for (int i = 0; i < lv.Columns.Count; i++)
                {
                    int imInd = ((Column)lv.Columns[i].Tag).Flt == "" ? 9 : 12;
                    switch ((lv.Columns[i].Tag as Column).Tp)
                    {
                        case ColumnType.Name: if (AMVInfo.SortMode == AMVInfo.SortMODE.Name) imInd += AMVInfo.SortDesc ? 2 : 1; break;
                        case ColumnType.Rating: if (AMVInfo.SortMode == AMVInfo.SortMODE.Rating) imInd += AMVInfo.SortDesc ? 2 : 1; break;
                    }
                    lv.Columns[i].ImageIndex = imInd;
                }

                List<string> notEmptyTags = new List<string>();
                for (int i = 0; i < Gl.infoL.Count; i++)
                {
                    bool tagInFilter;
                    if (RecInFlt(Gl.infoL[i], out tagInFilter))
                    {
                        tmpAmvShowList.Add(Gl.infoL[i]);
                    }

                    if (tagInFilter)
                    {
                        foreach (string recTag in Gl.infoL[i].TagGenre)
                            if (!notEmptyTags.Contains(recTag))
                                notEmptyTags.Add(recTag);
                        foreach (string recTag in Gl.infoL[i].TagOther)
                            if (!notEmptyTags.Contains(recTag))
                                notEmptyTags.Add(recTag);
                    }
                }

                EmptyTags = GetAllTags();
                foreach (string notEmptyTag in notEmptyTags) if (EmptyTags.Contains(notEmptyTag)) EmptyTags.Remove(notEmptyTag);

                tmpAmvShowList.Sort();

                // выставляем новый список
                lv.VirtualListSize = tmpAmvShowList.Count;
                AmvShowList = tmpAmvShowList;
                lv.Refresh();

                lblLen.Text = AmvShowList.Count.ToString() + "\\" + Gl.infoL.Count.ToString();

                int indEnsureVisible = -1;
                try
                {
                    // поиск выделенного элемента (после сортировки)
                    lv.SelectedIndices.Clear();
                    for (int i = 0; i < AmvShowList.Count; i++)
                    {
                        if (selectedRecs.Contains(AmvShowList[i]))
                        {
                            if (indEnsureVisible == -1) indEnsureVisible = i;
                            lv.SelectedIndices.Add(i);
                        }
                    }

                    if (indEnsureVisible != -1) AmvShowList[indEnsureVisible].Itm.EnsureVisible();
                }
                catch (Exception ex)
                {
                    Gl.WriteLog("ОШИБКА установки выделенного элемента при перерисовке ", "SelectedIndex=" + indEnsureVisible.ToString() + " AmvShowList.Count=" + AmvShowList.Count.ToString(), ex);
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(200);
                }


                // обновление иконок 
                ReFillInfo();
                ResetIcoAndColorTags();
            }
            catch (Exception ex) { Gl.WriteLog("ОШИБКА перезаполнения списка AMV", "AmvShowList.Count=" + AmvShowList.Count.ToString(), ex); }

        }

        public void UpdateItm(ListViewItem itm, ListView.ColumnHeaderCollection Columns, AMVInfo aInf)
        {
            aInf.LocalAMVInd = -1;
            // если количество столбцов поменялось
            while (Columns.Count < itm.SubItems.Count) itm.SubItems.RemoveAt(itm.SubItems.Count - 1);
            while (Columns.Count > itm.SubItems.Count) itm.SubItems.Add("");

            itm.ImageIndex = 0;
            if (aInf.Site == SITE.Akross) itm.ImageIndex = 1;
            if (aInf.Site == SITE.CreaCon) itm.ImageIndex = 2;
            // проверка, есть ли AMV локально
            bool bLocal = false;
            for (int i = 0; i < Gl.DB.Count; i++)
            {
                if (aInf.Site == SITE.AMVNews && Gl.DB[i].AMVNewsNum == aInf.Number) { itm.ImageIndex += 3; aInf.LocalAMVInd = i; bLocal = true; break; }
                if (aInf.Site == SITE.Akross && Gl.DB[i].AkrossNum == aInf.Number) { itm.ImageIndex += 3; aInf.LocalAMVInd = i; bLocal = true; break; }
                if (aInf.Site == SITE.CreaCon && Gl.DB[i].CreaConNum == aInf.Number) { itm.ImageIndex += 3; aInf.LocalAMVInd = i; bLocal = true; break; }
            }
            if (!bLocal && aInf.Watched) itm.ImageIndex += 6;

            itm.SubItems[0].Text = aInf.Name;
            for (int g = 1; g < Columns.Count; g++)
            {
                Column clm = (Column)Columns[g].Tag;

                switch (clm.Tp)
                {
                    case ColumnType.Rating:
                        {
                            itm.SubItems[g].Text = aInf.Rating == 0 ? "" : aInf.Rating.ToString();
                            break;
                        }
                    case ColumnType.Author:
                        {
                            string str = "";
                            for (int j = 0; j < aInf.Atr.Count; j++)
                            {
                                if (j > 0) str += " || ";
                                str += aInf.Atr[j];
                            }
                            itm.SubItems[g].Text = str;
                            break;
                        }
                    case ColumnType.Music:
                        {
                            string str = "";
                            for (int j = 0; j < aInf.Msc.Count; j++)
                            {
                                if (j > 0) str += " || ";
                                str += aInf.Msc[j];
                            }
                            itm.SubItems[g].Text = str;
                            break;
                        }

                    case ColumnType.Anime:
                        {
                            string str = "";
                            for (int j = 0; j < aInf.Anm.Count; j++)
                            {
                                if (j > 0) str += " || ";
                                str += aInf.Anm[j];
                            }
                            itm.SubItems[g].Text = str;
                            break;
                        }

                    case ColumnType.Tag:
                        {
                            string str = "";
                            for (int j = 0; j < aInf.TagGenre.Count; j++)
                            {
                                if (j > 0) str += " || ";
                                str += aInf.TagGenre[j];
                            }
                            for (int j = 0; j < aInf.TagOther.Count; j++)
                            {
                                if (str != "") str += " || ";
                                str += aInf.TagOther[j];
                            }
                            itm.SubItems[g].Text = str;
                            break;
                        }

                    case ColumnType.Awards:
                        {
                            string str = "";
                            for (int j = 0; j < aInf.Awd.Count; j++)
                            {
                                if (j > 0) str += ", ";
                                str += aInf.Awd[j];
                            }
                            itm.SubItems[g].Text = str;
                            break;
                        }
                }
            }

        }

        void ReFillInfo()
        {
            if (SelAmv == null || lv.SelectedIndices.Count > 1) { txbInfo.Text = ""; return; }

            StringBuilder sb = new StringBuilder();

            // авторы
            sb.Append(SelAmv.Atr.Count > 1 ? "АВТОРЫ: " : "АВТОР: ");
            if (SelAmv.Atr.Count > 0)
            {
                sb.Append(SelAmv.Atr[0]);
                for (int i = 1; i < SelAmv.Atr.Count; i++) sb.Append(" || " + SelAmv.Atr[i]);
            }
            sb.Append("\r\n");

            // музыка
            sb.Append("МУЗЫКА: ");
            if (SelAmv.Msc.Count > 0)
            {
                sb.Append(SelAmv.Msc[0]);
                for (int i = 1; i < SelAmv.Msc.Count; i++) sb.Append(" || " + SelAmv.Msc[i]);
            }
            sb.Append("\r\n");

            // награды
            sb.Append("НАГРАДЫ: ");
            if (SelAmv.Awd.Count > 0)
            {
                if (SelAmv.Awd.Count == 1)
                {
                    sb.Append(SelAmv.Awd[0]);
                }
                else
                {
                    sb.Append("\r\n\t" + SelAmv.Awd[0]);
                    for (int i = 1; i < SelAmv.Awd.Count; i++) sb.Append("\r\n\t" + SelAmv.Awd[i]);
                }
            }
            sb.Append("\r\n");

            // рейтинг
            sb.Append("ОЦЕНКА: " + SelAmv.Rating.ToString());

            sb.Append("\r\n\r\n");

            // коментарий
            sb.Append("*** КОМЕНТАРИЙ **************************************************\r\n");
            sb.Append(SelAmv.Comment);
            sb.Append("\r\n*************************************************************************\r\n");

            // список аниме
            if (SelAmv.Anm.Count > 0)
            {
                sb.Append("АНИМЕ:" + SelAmv.Anm[0]);
                for (int i = 1; i < SelAmv.Anm.Count; i++) sb.Append(" || " + SelAmv.Anm[i]);
            }
            sb.Append("\r\n*************************************************************************\r\n");

            // теги
            sb.Append("ТЕГИ" + ": ");
            if (SelAmv.TagGenre.Count > 0)
            {
                bool bFirst = false;
                foreach (string s in SelAmv.TagGenre)
                {
                    if (!bFirst) sb.Append(" || ");
                    sb.Append(s);
                }
                foreach (string s in SelAmv.TagOther)
                {
                    if (!bFirst) sb.Append(" || ");
                    sb.Append(s);
                }
            }
            sb.Append("\r\n*************************************************************************\r\n");

            txbInfo.Text = sb.ToString();
        }

        bool RecInFlt(AMVInfo amv, out bool TagInFilter)
        {
            TagInFilter = false;

            #region *** общие фильтры *********

            bool bFind = false;
            string genFlt = tTxbGeneralFlt.Text.Trim();
            if (genFlt != "")
            {
                foreach (Column clm in ClmL)
                {
                    if (clm.Tp != ColumnType.Len && clm.Tp != ColumnType.FPath && clm.Tp != ColumnType.KeyWords)
                        if (CellInFlt(amv, clm.Tp, genFlt)) { bFind = true; break; }
                }
                // комментарий
                if (tBtnIncludeCommentInFlt.Checked)
                    if (amv.Comment.ToUpper().Contains(genFlt.ToUpper())) bFind = true;
                if (!bFind) return false;
            }

            if (tBtnShowOnlyNotExist.Checked && amv.LocalAMVInd != -1) return false;

            bFind = false;
            if (tBtnShowOnlyAMVNews.Checked || tBtnShowOnlyAkross.Checked || tBtnShowOnlyCreaCon.Checked)
            {
                if (tBtnShowOnlyAMVNews.Checked && amv.Site == SITE.AMVNews) bFind = true;
                if (tBtnShowOnlyAkross.Checked && amv.Site == SITE.Akross) bFind = true;
                if (tBtnShowOnlyCreaCon.Checked && amv.Site == SITE.CreaCon) bFind = true;
                if (!bFind) return false;
            }
            #endregion *** общие фильтры *********

            // фильтры столбцов
            foreach (Column clm in ClmL)
            {
                if (!CellInFlt(amv, clm.Tp, clm.Flt)) return false;
            }

            // исключенные теги
            if (ExTags.Count > 0)
            {
                foreach (string exTag in ExTags)
                {
                    if (amv.TagGenre.Contains(exTag) || amv.TagOther.Contains(exTag)) return false;
                }
            }

            // закрепленные теги (в записи должны быть все закрепленные теги. Иначе, возвращаем false)
            if (FixTags.Count > 0)
            {
                foreach (string fixTag in FixTags)
                {
                    if (!amv.TagGenre.Contains(fixTag) && !amv.TagOther.Contains(fixTag)) return false;
                }
            }

            TagInFilter = true;

            // фильтр по выделенным тегам
            if (lvTags.SelectedItems.Count > 0)
            {
                bFind = false;
                List<string> selTags = GetAllSelectedTags();
                foreach (string selTag in selTags)
                {
                    if (amv.TagGenre.Contains(selTag)) { bFind = true; break; }
                    if (bFind) break;
                    if (amv.TagOther.Contains(selTag)) { bFind = true; break; }
                    if (bFind) break;
                }
                if (!bFind) return false;
            }

            return true;
        }

        bool CellInFlt(AMVInfo amv, ColumnType Tp, string Flt)
        {
            string FLT = Flt.ToUpper();

            switch (Tp)
            {
                // Имя
                case ColumnType.Name:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Name.Trim() != "") return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Name.Trim() == "") return false;
                            }
                            else if (amv.Name.ToUpper().IndexOf(FLT) == -1)
                                return false;
                        }
                        break;
                    }

                // рейтинг
                case ColumnType.Rating:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Rating != 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Rating == 0) return false;
                            }
                            else
                            {
                                if (FLT.StartsWith(">"))
                                {
                                    decimal val;
                                    if (!decimal.TryParse(FLT.Substring(1).Trim().Replace('.', ','), out val)) return false;
                                    if (amv.Rating <= val) return false;
                                }
                                else if (FLT.StartsWith("<"))
                                {
                                    decimal val;
                                    if (!decimal.TryParse(FLT.Substring(1).Trim().Replace('.', ','), out val)) return false;
                                    if (amv.Rating >= val) return false;
                                }
                                else return false;
                            }

                        }
                        break;
                    }

                // автор
                case ColumnType.Author:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Atr.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Atr.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Atr.Count == 0) return false;
                                // если хотябы в одной строке есть совпадение, amv можно добавлять
                                bool bExist = false;
                                for (int j = 0; j < amv.Atr.Count; j++)
                                    if (amv.Atr[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // музыка       
                case ColumnType.Music:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Msc.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Msc.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Msc.Count == 0) return false;
                                // если хотябы в одной строке есть совпадение, amv можно добавлять
                                bool bExist = false;
                                for (int j = 0; j < amv.Msc.Count; j++)
                                    if (amv.Msc[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // аниме
                case ColumnType.Anime:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Anm.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Anm.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Anm.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.Anm.Count; j++)
                                    if (amv.Anm[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // теги
                case ColumnType.Tag:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.TagGenre.Count > 0 || amv.TagOther.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.TagGenre.Count == 0 && amv.TagOther.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.TagGenre.Count == 0 && amv.TagOther.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.TagGenre.Count; j++)
                                    if (amv.TagGenre[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist)
                                {
                                    for (int j = 0; j < amv.TagOther.Count; j++)
                                        if (amv.TagOther[j].ToUpper().IndexOf(FLT) != -1)
                                        {
                                            bExist = true;
                                            break;
                                        }
                                }
                                if (!bExist) return false;
                            }
                        }
                        break;
                    }

                // награды
                case ColumnType.Awards:
                    {
                        if (FLT != "")
                        {
                            if (FLT == "<NULL>")
                            {
                                if (amv.Awd.Count > 0) return false;
                            }
                            else if (FLT == "<!NULL>")
                            {
                                if (amv.Awd.Count == 0) return false;
                            }
                            else
                            {
                                if (amv.Awd.Count == 0) return false;
                                bool bExist = false;
                                for (int j = 0; j < amv.Awd.Count; j++)
                                    if (amv.Awd[j].ToUpper().IndexOf(FLT) != -1)
                                    {
                                        bExist = true;
                                        break;
                                    }
                                if (!bExist) return false;
                            }

                        }
                        break;
                    }
            }
            return true;
        }

        private void FormAmvInfo_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            Hide();
        }

        private void lv_SelectedIndexChanged(object sender, EventArgs e)
        {
            ReFillInfo();
        }

        private void lv_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
            /*AMVInfo aInf = AmvShowList[e.ItemIndex];

            ListViewItem itm = new ListViewItem(aInf.Name);
            UpdateItm(itm, lv.Columns, aInf);
            e.Item = itm;*/
            e.Item = AmvShowList[e.ItemIndex].Itm;
        }

        private void tmrGeneralFlt_Tick(object sender, EventArgs e)
        {
            ReFillAmvInfo(true);
            SetFltIco();
            tmrGeneralFlt.Stop();
        }

        private void tTxbGeneralFlt_TextChanged(object sender, EventArgs e)
        {
            tmrGeneralFlt.Stop();
            tmrGeneralFlt.Start();
        }

        private void lv_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (SelAmv != null)
            {
                switch (SelAmv.Site)
                {
                    case SITE.AMVNews: Gl.OpenOnAMVNews(SelAmv.Number); break;
                    case SITE.Akross: Gl.OpenOnAkross(SelAmv.Number); break;
                    case SITE.CreaCon: Gl.OpenOnCreaCon(SelAmv.Number); break;
                }
            }
        }

        #region *** Работа с тегами *********

        /// <summary>Получение всех тегов из AMVInfo листа</summary>
        List<string> GetAllTags()
        {
            List<string> ret = new List<string>();
            foreach (AMVInfo inf in Gl.infoL)
            {
                foreach (string tag in inf.TagGenre)
                    if (!ret.Contains(tag))
                        ret.Add(tag);
                foreach (string tag in inf.TagOther)
                    if (!ret.Contains(tag))
                        ret.Add(tag);
            }
            return ret;
        }

        /// <summary>Получение всех тегов из AMVInfo листа</summary>
        List<string> GetGenreTags()
        {
            List<string> ret = new List<string>();
            foreach (AMVInfo inf in Gl.infoL)
            {
                foreach (string tag in inf.TagGenre)
                    if (!ret.Contains(tag))
                        ret.Add(tag);
            }
            return ret;
        }

        /// <summary>Получение всех тегов из AMVInfo листа</summary>
        List<string> GetOtherTags()
        {
            List<string> ret = new List<string>();
            foreach (AMVInfo inf in Gl.infoL)
            {
                foreach (string tag in inf.TagOther)
                    if (!ret.Contains(tag))
                        ret.Add(tag);
            }
            return ret;
        }

        bool bInOtherTagDir = false;

        /// <summary> Перезаполнение листа тегов для фильтров </summary>
        void RefillLvTags()
        {
            lvTags.Items.Clear();

            if (bInOtherTagDir)
            {
                // ссылка выхода
                ListViewItem itm = new ListViewItem("..");
                itm.Tag = null;
                lvTags.Items.Add(itm);
                // теги
                List<string> tagL = GetOtherTags();
                tagL.Sort();
                for (int i = 0; i < tagL.Count; i++)
                {
                    itm = new ListViewItem(tagL[i]);
                    itm.Tag = tagL[i];
                    lvTags.Items.Add(itm);
                }
            }
            else
            {
                // каталог для прочих тегов
                ListViewItem itm = new ListViewItem("Прочие теги");
                itm.Tag = null;
                lvTags.Items.Add(itm);
                // теги
                List<string> tagL = GetGenreTags();
                tagL.Sort();
                for (int i = 0; i < tagL.Count; i++)
                {
                    itm = new ListViewItem(tagL[i]);
                    itm.Tag = tagL[i];
                    lvTags.Items.Add(itm);
                }
            }
            ResetIcoAndColorTags();
            SetFltIco();
        }

        private void lvTags_SelectedIndexChanged(object sender, EventArgs e)
        {
            //
        }

        private void lvTags_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Middle)
            {
                // исключение тега по клику колесиком
                ListViewItem itm = lvTags.GetItemAt(e.X, e.Y);
                if (itm != null)
                {
                    string tagName = (string)itm.Tag;
                    // если тег уже в исключенных, убираем его оттуда
                    if (ExTags.Contains(itm.Text)) DeleteFromExTagList(tagName);
                    // иначе исключаем
                    else AddInExTagList(tagName);
                }
            }

            ReFillAmvInfo(true);
            ResetIcoAndColorTags();
            SetFltIco();
        }

        private void lvTags_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lvTags.SelectedIndices.Count == 0) return;
            if (lvTags.SelectedIndices[0] == 0)
            {
                bInOtherTagDir = !bInOtherTagDir;
                RefillLvTags();
            }
            else
            {
                string tagName = (string)lvTags.SelectedItems[0].Tag;
                if (FixTags.Contains(tagName))
                {
                    FixTags.Remove(tagName);
                    ReFillAmvInfo(true);
                    ResetIcoAndColorTags();
                }
                else if (!EmptyTags.Contains(tagName))
                {
                    FixTags.Add(tagName);
                    ReFillAmvInfo(true);
                    ResetIcoAndColorTags();
                }
            }

        }

        private void lvTags_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (lvTags.SelectedItems.Count > 0 && lvTags.SelectedIndices[0] == 0)
                {
                    lvTags_MouseDoubleClick(null, null);
                }
            }
            if (e.KeyCode == Keys.Back)
            {
                if (bInOtherTagDir)
                {
                    lvTags.SelectedIndices.Clear();
                    lvTags.SelectedIndices.Add(0);
                    lvTags_MouseDoubleClick(null, null);
                }
            }
            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
            {
                ReFillAmvInfo(true);
                SetFltIco();
            }
        }

        void AddInExTagList(string Tag)
        {
            if (!ExTags.Contains(Tag)) ExTags.Add(Tag);
            if (FixTags.Contains(Tag)) FixTags.Remove(Tag);
        }

        void DeleteFromExTagList(string Tag)
        {
            if (ExTags.Contains(Tag)) ExTags.Remove(Tag);
        }

        void ResetIcoAndColorTags()
        {
            foreach (ListViewItem itm in lvTags.Items)
            {
                if (itm.Tag == null)
                {
                    itm.ImageIndex = 0;
                    continue;
                }

                string tagName = (string)itm.Tag;

                itm.ImageIndex = 6;
                itm.ForeColor = Color.Black;

                //если тег в исключенных
                if (ExTags.Contains(tagName))
                {
                    itm.ImageIndex = 7;
                    itm.ForeColor = clrDisabledItem;
                }

                // закрепленные теги
                if (FixTags.Count > 0)
                {
                    //если тег в закрепленных
                    if (FixTags.Contains(tagName))
                    {
                        itm.ImageIndex = 8;
                        itm.ForeColor = Color.Blue;
                    }
                }

                if (EmptyTags.Count > 0 && itm.ImageIndex == 6)
                {
                    // пустые теги
                    if (itm.ImageIndex == 6)
                    {
                        if (EmptyTags.Contains(tagName))
                        {
                            itm.ImageIndex = 9;
                            itm.ForeColor = Color.Gray;
                        }
                    }
                }
            }
        }

        List<string> GetAllSelectedTags()
        {
            List<string> ret = new List<string>();
            foreach (ListViewItem selItm in lvTags.SelectedItems)
            {
                ret.Add((string)selItm.Tag);
            }
            return ret;
        }

        #endregion *** Работа с тегами *********

        bool bFltActive = false;
        void SetFltIco()
        {
            // кнопка сброса всех фильтров
            tBtnClearFlt.Enabled = IsFltActive(false);
            // отображение активности прочих фильтров
            if (IsFltActive(true))
            {
                if (!bFltActive)
                {
                    tBtnFlt.Image = Properties.Resources.flt_on;
                    bFltActive = true;
                }
            }
            else
            {
                if (bFltActive)
                {
                    tBtnFlt.Image = Properties.Resources.flt_off;
                    bFltActive = false;
                }
            }
        }

        bool IsFltActive(bool bOnlyOthrFlt)
        {
            if (!bOnlyOthrFlt)
            {
                if (tTxbGeneralFlt.Text != "") return true;
                if (ExTags.Count > 0) return true;
                if (FixTags.Count > 0) return true;
                foreach (Column clm in ClmL) if (clm.Flt != "") return true;  // фильтры по колонкам
                if (lvTags.SelectedItems.Count > 0) return true;    // фильтр по тегам
            }
            if (tBtnShowOnlyAMVNews.Checked) return true;
            if (tBtnShowOnlyAkross.Checked) return true;
            if (tBtnShowOnlyCreaCon.Checked) return true;
            if (tBtnShowOnlyNotExist.Checked) return true;
            return false;
        }

        private void tBtnClearFlt_Click(object sender, EventArgs e)
        {
            tBtnShowOnlyAMVNews.Checked = false;
            tBtnShowOnlyAkross.Checked = false;
            tBtnShowOnlyCreaCon.Checked = false;
            tBtnShowOnlyNotExist.Checked = false;
            for (int i = 0; i < lv.Columns.Count; i++) ((Column)lv.Columns[i].Tag).Flt = "";
            lvTags.SelectedItems.Clear();
            ExTags.Clear();
            FixTags.Clear();
            EmptyTags.Clear();

            // удаление текста из общего фильтра автоматом обновит список AMV (если он есть)
            if (tTxbGeneralFlt.Text != "") tTxbGeneralFlt.Text = "";
            else ReFillAmvInfo(true);

            SetFltIco();
        }

        private void lv_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (tBtnSortMode.Checked)
            {
                AMVInfo.SortMODE sortM = AMVInfo.SortMODE.Name;
                switch (ClmL[e.Column].Tp)
                {
                    case ColumnType.Name: sortM = AMVInfo.SortMODE.Name; break;
                    case ColumnType.Rating: sortM = AMVInfo.SortMODE.Rating; break;
                }

                if (AMVInfo.SortMode != sortM)
                {
                    AMVInfo.SortDesc = false;
                    AMVInfo.SortMode = sortM;
                }
                else
                {
                    /*if (AMVInfo.SortDesc)
                    {
                        AMVInfo.SortDesc = false;
                        AMVInfo.SortMode = AMVInfo.SortMODE.Name;
                    }
                    else AMVInfo.SortDesc = true;*/
                    AMVInfo.SortDesc = !AMVInfo.SortDesc;
                }
                ReFillAmvInfo(true);
            }
            else
            {
                using (ESpace.FormEditValue frmEdit = new ESpace.FormEditValue())
                {
                    frmEdit.SetParams("", 200, null, "");
                    if (frmEdit.ShowDialog(((Column)lv.Columns[e.Column].Tag).Flt, false))
                    {
                        ((Column)lv.Columns[e.Column].Tag).Flt = (string)frmEdit.Value;
                        ReFillAmvInfo(true);
                        SetFltIco();
                    }
                }
            }
        }

        private void tBtnShowOnly_Click(object sender, EventArgs e)
        {
            SetFltIco();
            ReFillAmvInfo(true);
        }

        private void menuAmvList_Opening(object sender, CancelEventArgs e)
        {
            mBtnOpenLocal.Enabled = SelAmv != null && SelAmv.LocalAMVInd != -1;
            mBtnSetAsWatch.Enabled = SelAmv != null && !SelAmv.Watched;
            mBtnResetAsWatch.Enabled = SelAmv != null && SelAmv.Watched;
        }

        private void mBtnOpenLocal_Click(object sender, EventArgs e)
        {
            if (SelAmv != null && SelAmv.LocalAMVInd != -1)
                Gl.OpenAmv(Gl.DB[SelAmv.LocalAMVInd]);
        }

        private void mBtnSetAsWatch_Click(object sender, EventArgs e)
        {
            SelAmv.Watched = true;
            SaveWatch();
            UpdateItm(SelAmv.Itm, lv.Columns, SelAmv);
            lv.Refresh();
        }

        private void mBtnResetAsWatch_Click(object sender, EventArgs e)
        {
            SelAmv.Watched = false;
            SaveWatch();
            UpdateItm(SelAmv.Itm, lv.Columns, SelAmv);
            lv.Refresh();
        }

        /// <summary>Загрузить список посмотренного</summary>
        void LoadWatch()
        {
            string fPathWatch = Gl.dPathAmvInfo + "\\Watched.wtch";
            foreach (AMVInfo aInf in Gl.infoL) aInf.Watched = false;
            if (!File.Exists(fPathWatch)) return;

            // копирование в историю
            string dPathWatchHist = Gl.dPathAmvInfo + "\\WatchHist";
            if (!Directory.Exists(dPathWatchHist)) Directory.CreateDirectory(dPathWatchHist);
            File.Copy(fPathWatch, dPathWatchHist + "\\watch_" + DateTime.Now.ToString("yyyy_MM_dd") + ".wtch", true);

            // загрузка
            string[] strL = File.ReadAllLines(fPathWatch, Encoding.UTF8);
            bool bErr = false;
            foreach (string str in strL)
            {
                string[] sl = str.Trim().Split(';');
                if (sl.Length < 2) continue;
                try
                {
                    SITE site = (SITE)Enum.Parse(typeof(SITE), sl[0].Trim());
                    int num = Convert.ToInt32(sl[1].Trim());
                    foreach (AMVInfo aInf in Gl.infoL)
                    {
                        if (site == aInf.Site && num == aInf.Number)
                            aInf.Watched = true;
                    }
                }
                catch { bErr = true; }
            }
            if (bErr) MessageBox.Show("Внимание! При загрузке инормации о просмотренных AMV возникли ошибки. Часть информации об отметках просмотра может быть утеряна");
        }

        /// <summary>Сохранить список посмотренного</summary>
        void SaveWatch()
        {
            StringBuilder sb = new StringBuilder();
            foreach (AMVInfo aInf in Gl.infoL)
                if (aInf.Watched)
                    sb.AppendLine(aInf.Site.ToString() + ";" + aInf.Number + ";");
            File.WriteAllText(Gl.dPathAmvInfo + "\\Watched.wtch", sb.ToString(), Encoding.UTF8);
        }

        private void tBtnIncludeCommentInFlt_Click(object sender, EventArgs e)
        {
            SetFltIco();
            ReFillAmvInfo(true);
        }

    }
}
